home *** CD-ROM | disk | FTP | other *** search
/ Openstep 4.2 (Developer) / Openstep Developer 4.2.iso / NextDeveloper / Examples / AppKit / Lines / UserPath.m < prev   
Encoding:
Text File  |  1997-01-13  |  7.7 KB  |  275 lines

  1. /* 
  2.  * UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
  3.  * Converted into an object Jan '97 by Ali Ozer
  4.  *
  5.  * You may freely copy, distribute, and re-use the code in this example. NeXT
  6.  * disclaims any warranty of any kind, expressed or implied, as to its fitness
  7.  * for any particular purpose.
  8.  */
  9.  
  10. #import "UserPath.h"
  11. #import <AppKit/NSGraphics.h>
  12. #import <AppKit/NSErrors.h>
  13. #import <math.h>
  14.  
  15. @implementation UserPath
  16.  
  17. - (id)init {
  18.     [super init];
  19.     max = 32;
  20.     points = NSZoneMalloc([self zone], sizeof(float) * max);
  21.     ops = NSZoneMalloc([self zone], (2 + (max / 2)) * sizeof(char));
  22.     ping = NO;
  23.     
  24.     return self;
  25. }
  26.  
  27. /* Frees User Path and its associated buffers
  28. */
  29. - (void)dealloc {
  30.     free(points);
  31.     free(ops);
  32.     [super dealloc];
  33. }
  34.  
  35. /* grows the  associated buffers as necessary. buffer size doubles on each call. You never need to call grow directly as it is called as needed by the methods and functions which add elements into the buffer
  36. */
  37. - (void)growUserPath {
  38.     /* double the size of the internal buffers */
  39.     max *= 2;
  40.     points = NSZoneRealloc([self zone], points, sizeof(float) * max);
  41.     ops = NSZoneRealloc([self zone], ops, (2 + (max / 2)) * sizeof(char));
  42. }
  43.  
  44. /* Call this to start generating a user path. The cache argument specifies if you want the user path cached at the server (i.e. dps_ucache). If a path needs to be drawn repeatedly, it might make sense to cache it down in the server. In either case, the UserPath object will automatically calculate the bounding box for the path and add the dps_setbbox operator.
  45. */
  46. - (void)beginUserPath:(BOOL)cache {
  47.     numberOfPoints = numberOfOps = 0;
  48.     cp.x = cp.y = 0;
  49.     bbox[0] = bbox[1] = 1.0e6;
  50.     bbox[2] = bbox[3] = -1.0e6;
  51.     if (cache) {
  52.     ops[numberOfOps++] = dps_ucache;
  53.     }
  54.     ops[numberOfOps++] = dps_setbbox;
  55.     opForUserPath = 0;
  56. }
  57.  
  58. /* Call this to stop filling the path. Note this does not send the userpath to the server -- use sendUserPath. The op argument should be one of the following:
  59.     dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
  60.     dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
  61.   These are defined in <dpsclient/dpsNext.h.  
  62. */
  63. - (void)endUserPath:(int)op {
  64.     opForUserPath = op;
  65. }
  66.  
  67. /* Sets ping to YES so that after each time a user path is sent down to the window server, an ping is sent after. The purpose is to catch PostScript errors that may be generated by the user path.  Normally ping is NO. 
  68. */
  69. - (void)setSynchronous:(BOOL)shouldPing {
  70.     ping = shouldPing;
  71. }
  72.  
  73. - (BOOL)isSynchronous {
  74.     return ping;
  75. }
  76.  
  77. /* Call this to send the path down to the server. If ping==YES (set via debug:), the function will send an NXPing() after the Path.
  78. */
  79. - (void)sendUserPath {
  80.     if (opForUserPath != 0) {
  81.         PSDoUserPath(points, numberOfPoints, dps_float, ops, numberOfOps, bbox, opForUserPath);
  82.         if (ping) {
  83.             PSWait();
  84.         }
  85.     }
  86. }
  87.  
  88. /* Checks if bounding box needs to be enlarged based on x and y 
  89. */
  90. - (void)checkBoundingBox:(float)x :(float)y {
  91.     if (x < bbox[0]) {
  92.     bbox[0] = x;
  93.     }
  94.     if (y < bbox[1]) {
  95.     bbox[1] = y;
  96.     }
  97.     if (x > bbox[2]) {
  98.     bbox[2] = x;
  99.     }
  100.     if (y > bbox[3]) {
  101.     bbox[3] = y;
  102.     }
  103. }
  104.  
  105. /* adds x and y to user path. Updates bounding box as necessary
  106. */
  107. - (void)addPts:(float)x :(float)y {
  108.     if (!((numberOfPoints + 2) < max)) {
  109.     [self growUserPath];
  110.     }
  111.     points[numberOfPoints++] = x;
  112.     points[numberOfPoints++] = y;
  113.     [self checkBoundingBox:x :y];
  114. }
  115.  
  116. /* adds operator to user path.  Operator should be one of the following:
  117.     dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
  118.     dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
  119. */
  120. - (void)addOp:(int)op {
  121.     ops[numberOfOps++] = op;
  122. }
  123.  
  124. /* adds operator and x and y to user path. Operator should be one of the operators above
  125. */
  126. - (void)add:(int)op :(float)x :(float)y {
  127.     if (!((numberOfPoints + 2) < max)) {
  128.     [self growUserPath];
  129.     }
  130.     ops[numberOfOps++] = op;
  131.     points[numberOfPoints++] = x;
  132.     points[numberOfPoints++] = y;
  133.     [self checkBoundingBox:x :y];
  134. }
  135.  
  136. /* adds <x y moveto> to user path and updates bounding box 
  137. */
  138. - (void)moveto:(float)x :(float)y {
  139.     [self add:dps_moveto :x :y];
  140.     cp.x = x;
  141.     cp.y = y;
  142. }
  143.  
  144. /* adds <x y rmoveto> to user path and updates bounding box 
  145. */
  146. - (void)rmoveto:(float)x :(float)y {
  147.     if (!((numberOfPoints + 2) < max)) {
  148.     [self growUserPath];
  149.     }
  150.     ops[numberOfOps++] = dps_rmoveto;
  151.     points[numberOfPoints++] = x;
  152.     points[numberOfPoints++] = y;
  153.     cp.x += x;
  154.     cp.y += y;
  155.     [self checkBoundingBox:cp.x :cp.y];
  156. }
  157.  
  158. /* adds <x y lineto> to user path and updates bounding box 
  159. */
  160. - (void)lineto:(float)x :(float)y {
  161.     [self add:dps_lineto :x :y];
  162.     cp.x = x;
  163.     cp.y = y;
  164. }
  165.  
  166. /* adds <x y rlineto> to user path and updates bounding box 
  167. */
  168. - (void)rlineto:(float)x :(float)y {
  169.     if (!((numberOfPoints + 2) < max)) {
  170.     [self growUserPath];
  171.     }
  172.     ops[numberOfOps++] = dps_rlineto;
  173.     points[numberOfPoints++] = x;
  174.     points[numberOfPoints++] = y;
  175.     cp.x += x;
  176.     cp.y += y;
  177.     [self checkBoundingBox:cp.x :cp.y];
  178. }
  179.  
  180. /* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box
  181. */
  182. - (void)curveto:(float)x1 :(float)y1 :(float)x2 :(float)y2 :(float)x3 :(float)y3 {
  183.     [self addPts:x1 :y1];
  184.     [self addPts:x2 :y2];
  185.     [self add:dps_curveto :x3 :y3];
  186.     cp.x = x3;
  187.     cp.y = y3;
  188. }
  189.  
  190. /* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box 
  191. */
  192. - (void)rcurveto:(float)dx1 :(float)dy1 :(float)dx2 :(float)dy2 :(float)dx3 :(float)dy3 {
  193.     if (!((numberOfPoints + 6) < max)) {
  194.     [self growUserPath];
  195.     }
  196.     ops[numberOfOps++] = dps_rcurveto;
  197.     points[numberOfPoints++] = dx1;
  198.     points[numberOfPoints++] = dy1;
  199.     points[numberOfPoints++] = dx2;
  200.     points[numberOfPoints++] = dy2;
  201.     points[numberOfPoints++] = dx3;
  202.     points[numberOfPoints++] = dy3;
  203.     [self checkBoundingBox:cp.x + dx1 :cp.y + dy1];
  204.     [self checkBoundingBox:cp.x + dx2 :cp.y + dy2];
  205.     [self checkBoundingBox:cp.x + dx3 :cp.y + dy3];
  206.     cp.x = dx3;
  207.     cp.y = dy3;
  208.  
  209.     return;
  210. }
  211.  
  212. /* adds <x y r ang1 ang2 arc> to user path and updates bounding box 
  213. */
  214. - (void)arc:(float)x :(float)y :(float)r :(float)ang1 :(float)ang2 {
  215.     if (!((numberOfPoints + 5) < max)) {
  216.     [self growUserPath];
  217.     }
  218.     ops[numberOfOps++] = dps_arc;
  219.     points[numberOfPoints++] = x;
  220.     points[numberOfPoints++] = y;
  221.     points[numberOfPoints++] = r;
  222.     points[numberOfPoints++] = ang1;
  223.     points[numberOfPoints++] = ang2;
  224.     [self checkBoundingBox:x + r :y + r];
  225.     [self checkBoundingBox:x - r :y - r];
  226.     cp.x = x + cos(ang2 / 57.3) * r;
  227.     cp.y = y + sin(ang2 / 57.3) * r;
  228. }
  229.  
  230. /* adds <x y r ang1 ang2 arcn> to user path and updates bounding box
  231. */
  232. - (void)arcn:(float)x :(float)y :(float)r :(float)ang1 :(float)ang2 {
  233.     if (!((numberOfPoints + 5) < max)) {
  234.     [self growUserPath];
  235.     }
  236.     ops[numberOfOps++] = dps_arcn;
  237.     points[numberOfPoints++] = x;
  238.     points[numberOfPoints++] = y;
  239.     points[numberOfPoints++] = r;
  240.     points[numberOfPoints++] = ang1;
  241.     points[numberOfPoints++] = ang2;
  242.     [self checkBoundingBox:x + r :y + r];
  243.     [self checkBoundingBox:x - r :y - r];
  244.     cp.x = x + cos(ang2 / 57.3) * r;
  245.     cp.y = y + sin(ang2 / 57.3) * r;
  246. }
  247.  
  248. /* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box 
  249. */
  250. - (void)arct:(float)x1 :(float)y1 :(float)x2 :(float)y2 :(float)r {
  251.     if (!((numberOfPoints + 5) < max)) {
  252.     [self growUserPath];
  253.     }
  254.     ops[numberOfOps++] = dps_arcn;
  255.     points[numberOfPoints++] = x1;
  256.     points[numberOfPoints++] = y1;
  257.     points[numberOfPoints++] = x2;
  258.     points[numberOfPoints++] = y2;
  259.     points[numberOfPoints++] = r;
  260.     [self checkBoundingBox:x1 :y1];
  261.     [self checkBoundingBox:x2 :y2];
  262.     cp.x = x2;
  263.     cp.y = y2;
  264. }
  265.  
  266. /* adds <closepath> to user path and updates bounding box
  267. */
  268. - (void)closepath {
  269.     ops[numberOfOps++] = dps_closepath;
  270. }
  271.  
  272. @end
  273.  
  274.  
  275.